{
 "metadata": {
  "signature": "sha256:0b6e88ecc426d176568b1e498f94e8772c574b1838cb2a391d2c6f1ac265cef9"
 },
 "nbformat": 3,
 "nbformat_minor": 0,
 "worksheets": [
  {
   "cells": [
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "SWIG memory deallocation\n",
      "========================\n",
      "\n",
      "Introduction\n",
      "------------\n",
      "\n",
      "### Recipe description\n",
      "\n",
      "This cookbook recipe describes the automatic deallocation of memory\n",
      "blocks allocated via \\`malloc()\\` calls in C, when the corresponding\n",
      "Python numpy array objects are destroyed. The recipe uses SWIG and a\n",
      "modified \\`numpy.i\\` helper file.\n",
      "\n",
      "To be more specific, new fragments were added to the existing\n",
      "\\`numpy.i\\` to handle automatic deallocation of arrays, the size of\n",
      "which is not known in advance. As with the original fragments, a block\n",
      "of \\`malloc()\\` memory can be converted into a returned numpy python\n",
      "object via a call to \\`PyArray\\_SimpleNewFromData()\\`. However, the\n",
      "returned python object is created using \\`PyCObject\\_FromVoidPtr()\\`,\n",
      "which ensures that the allocated memory is automatically disposed of\n",
      "when the Python object is destroyed. Examples below show how using these\n",
      "new fragments avoids leaking memory.\n",
      "\n",
      "Since the new fragments are based on the \\`\\_ARGOUTVIEW\\_\\` ones, the\n",
      "name \\`\\_ARGOUTVIEWM\\_\\` was chosen, where \\`M\\` stands for managed. All\n",
      "managed fragments (ARRAY1, 2 and 3, FARRAY1, 2 and 3) were implemented,\n",
      "and have now been extensively tested.\n",
      "\n",
      "### Where to get the files\n",
      "\n",
      "At the moment, the modified numpy.i file is available here (last updated\n",
      "2012-04-22): \\*\n",
      "<http://ezwidgets.googlecode.com/svn/trunk/numpy/numpy.i> \\*\n",
      "<http://ezwidgets.googlecode.com/svn/trunk/numpy/pyfragments.swg>\n",
      "\n",
      "### How the code came about\n",
      "\n",
      "The original memory deallocation code was written by Travis Oliphant\n",
      "(see <http://blog.enthought.com/?p=62> ) and as far as I know, these\n",
      "clever people were the first ones to use it in a swig file (see\n",
      "<http://niftilib.sourceforge.net/pynifti>, file nifticlib.i). Lisandro\n",
      "Dalcin then pointed out a simplified implementation using\n",
      "[CObjects](http://docs.python.org/c-api/cobject.html), which Travis\n",
      "details in this [updated blog\n",
      "post](http://blog.enthought.com/python/numpy/simplified-creation-of-numpy-arrays-from-pre-allocated-memory/).\n",
      "\n",
      "How to use the new fragments\n",
      "----------------------------\n",
      "\n",
      "### Important steps\n",
      "\n",
      "In yourfile.i, the %init function uses the same \\`import\\_array()\\` call\n",
      "you already know:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "%init %{\n",
      "    import_array();\n",
      "%}"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "... then just use ARGOUTVIEWM\\_ARRAY1 instead of ARGOUTVIEW\\_ARRAY1 and\n",
      "memory deallocation is handled automatically when the python array is\n",
      "destroyed (see examples below).\n",
      "\n",
      "A simple ARGOUTVIEWM\\_ARRAY1 example\n",
      "------------------------------------\n",
      "\n",
      "The SWIG-wrapped function in C creates an N integers array, using\n",
      "\\`malloc()\\` to allocate memory. From python, this function is\n",
      "repetitively called and the array created destroyed (M times).\n",
      "\n",
      "Using the ARGOUTVIEW\\_ARRAY1 provided in numpy.i, this will create\n",
      "memory leaks (I know ARGOUTVIEW\\_ARRAY1 has not been designed for this\n",
      "purpose but it's tempting!).\n",
      "\n",
      "Using the ARGOUTVIEWM\\_ARRAY1 fragment instead, the memory allocated\n",
      "with \\`malloc()\\` will be automatically deallocated when the array is\n",
      "deleted.\n",
      "\n",
      "The python test program creates and deletes a 1024\\^2 ints array 2048\n",
      "times using both ARGOUTVIEW\\_ARRAY1 and ARGOUTVIEWM\\_ARRAY1 and when\n",
      "memory allocation fails, an exception is generated in C and caught in\n",
      "Python, showing which iteration finally caused the allocation to fail.\n",
      "\n",
      "### The C source (ezalloc.c and ezalloc.h)\n",
      "\n",
      "Here is the\n",
      "[ezalloc.h](http://ezwidgets.googlecode.com/svn/trunk/numpy/ezalloc.h)\n",
      "file:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "void alloc(int ni, int** veco, int *n);"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Here is the\n",
      "[ezalloc.c](http://ezwidgets.googlecode.com/svn/trunk/numpy/ezalloc.c)\n",
      "file:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "#include <stdio.h>\n",
      "#include <errno.h>\n",
      "#include \"ezalloc.h\"\n",
      "\n",
      "void alloc(int ni, int** veco, int *n)\n",
      "{\n",
      "    int *temp;\n",
      "    temp = (int *)malloc(ni*sizeof(int));\n",
      "\n",
      "    if (temp == NULL)\n",
      "        errno = ENOMEM;\n",
      "\n",
      "    //veco is either NULL or pointing to the allocated block of memory...\n",
      "    *veco = temp;\n",
      "    *n = ni;\n",
      "}"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "### The interface file (ezalloc.i)\n",
      "\n",
      "The file (available here:\n",
      "[ezalloc.i](http://ezwidgets.googlecode.com/svn/trunk/numpy/ezalloc.i))\n",
      "does a couple of interesting things: \\* Like I said in the introduction,\n",
      "calling the \\`import\\_array()\\` function in the \\`%init\\` section now\n",
      "also initialises the memory deallocation code. There is nothing else to\n",
      "add here. \\* An exception is generated if memory allocation fails. After\n",
      "a few iterations of the code construct, using \\`errno\\` and\n",
      "\\`SWIG\\_fail\\` is the simplest I've come-up with. \\* In this example,\n",
      "two inline functions are created, one using ARGOUTVIEW\\_ARRAY1 and the\n",
      "other ARGOUTVIEWM\\_ARRAY1. Both function use the \\`alloc()\\` function\n",
      "(see ezalloc.h and ezalloc.c)."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "%module ezalloc\n",
      "%{\n",
      "#include <errno.h>\n",
      "#include \"ezalloc.h\"\n",
      "\n",
      "#define SWIG_FILE_WITH_INIT\n",
      "%}\n",
      "\n",
      "%include \"numpy.i\"\n",
      "\n",
      "%init %{\n",
      "    import_array();\n",
      "%}\n",
      "\n",
      "%apply (int** ARGOUTVIEWM_ARRAY1, int *DIM1) {(int** veco1, int* n1)}\n",
      "%apply (int** ARGOUTVIEW_ARRAY1, int *DIM1) {(int** veco2, int* n2)}\n",
      "\n",
      "%include \"ezalloc.h\"\n",
      "\n",
      "%exception\n",
      "{\n",
      "    errno = 0;\n",
      "    $action\n",
      "\n",
      "    if (errno != 0)\n",
      "    {\n",
      "        switch(errno)\n",
      "        {\n",
      "            case ENOMEM:\n",
      "                PyErr_Format(PyExc_MemoryError, \"Failed malloc()\");\n",
      "                break;\n",
      "            default:\n",
      "                PyErr_Format(PyExc_Exception, \"Unknown exception\");\n",
      "        }\n",
      "        SWIG_fail;\n",
      "    }\n",
      "}\n",
      "\n",
      "%rename (alloc_managed) my_alloc1;\n",
      "%rename (alloc_leaking) my_alloc2;\n",
      "\n",
      "%inline %{\n",
      "\n",
      "void my_alloc1(int ni, int** veco1, int *n1)\n",
      "{\n",
      "    /* The function... */\n",
      "    alloc(ni, veco1, n1);\n",
      "}\n",
      "\n",
      "void my_alloc2(int ni, int** veco2, int *n2)\n",
      "{\n",
      "    /* The function... */\n",
      "    alloc(ni, veco2, n2);\n",
      "}\n",
      "\n",
      "%}"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Don't forget that you will need the\n",
      "[numpy.i](http://ezwidgets.googlecode.com/svn/trunk/numpy/numpy.i) file\n",
      "in the same directory for this to compile.\n",
      "\n",
      "### Setup file (setup\\_alloc.py)\n",
      "\n",
      "This is the\n",
      "[setup\\_alloc.py](http://ezwidgets.googlecode.com/svn/trunk/numpy/setup_alloc.py)\n",
      "file:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "#! /usr/bin/env python\n",
      "\n",
      "# System imports\n",
      "from distutils.core import *\n",
      "from distutils      import sysconfig\n",
      "\n",
      "# Third-party modules - we depend on numpy for everything\n",
      "import numpy\n",
      "\n",
      "# Obtain the numpy include directory.  This logic works across numpy versions.\n",
      "try:\n",
      "    numpy_include = numpy.get_include()\n",
      "except AttributeError:\n",
      "    numpy_include = numpy.get_numpy_include()\n",
      "\n",
      "# alloc extension module\n",
      "_ezalloc = Extension(\"_ezalloc\",\n",
      "                   [\"ezalloc.i\",\"ezalloc.c\"],\n",
      "                   include_dirs = [numpy_include],\n",
      "\n",
      "                   extra_compile_args = [\"--verbose\"]\n",
      "                   )\n",
      "\n",
      "# NumyTypemapTests setup\n",
      "setup(  name        = \"alloc functions\",\n",
      "        description = \"Testing managed arrays\",\n",
      "        author      = \"Egor Zindy\",\n",
      "        version     = \"1.0\",\n",
      "        ext_modules = [_ezalloc]\n",
      "        )"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "### Compiling the module\n",
      "\n",
      "The setup command-line is (in Windows, using mingw):"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "$> python setup_alloc.py build --compiler=mingw32"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "or in UN\\*X, simply"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "$> python setup_alloc.py build"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "### Testing the module\n",
      "\n",
      "If everything goes according to plan, there should be a\n",
      "\\`\\_ezalloc.pyd\\` file available in the \\`build\\\\lib.XXX\\` directory.\n",
      "The file needs to be copied in the directory with the \\`ezalloc.py\\`\n",
      "file (generated by swig).\n",
      "\n",
      "A python test program is provided in the SVN repository\n",
      "([test\\_alloc.py](http://ezwidgets.googlecode.com/svn/trunk/numpy/test_alloc.py))\n",
      "and reproduced below:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "import ezalloc\n",
      "\n",
      "n = 2048\n",
      "\n",
      "# this multiplied by sizeof(int) to get size in bytes...\n",
      "#assuming sizeof(int)=4 on a 32bit machine (sorry, it's late!)\n",
      "m = 1024 * 1024\n",
      "err = 0\n",
      "\n",
      "print \"ARGOUTVIEWM_ARRAY1 (managed arrays) - %d allocations (%d bytes each)\" % (n,4*m)\n",
      "for i in range(n):\n",
      "    try:\n",
      "        #allocating some memory\n",
      "        a = ezalloc.alloc_managed(m)\n",
      "        #deleting the array\n",
      "        del a\n",
      "    except:\n",
      "        err = 1\n",
      "        print \"Step %d failed\" % i\n",
      "        break\n",
      "\n",
      "if err == 0:\n",
      "    print \"Done!\\n\"\n",
      "\n",
      "print \"ARGOUTVIEW_ARRAY1 (unmanaged, leaking) - %d allocations (%d bytes each)\" % (n,4*m)\n",
      "for i in range(n):\n",
      "    try:\n",
      "        #allocating some memory\n",
      "        a = ezalloc.alloc_leaking(m)\n",
      "        #deleting the array\n",
      "        del a\n",
      "    except:\n",
      "        err = 1\n",
      "        print \"Step %d failed\" % i\n",
      "        break\n",
      "\n",
      "if err == 0:\n",
      "    print \"Done? Increase n!\\n\""
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Then, a"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "$> python test_alloc.py"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "will produce an output similar to this:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "ARGOUTVIEWM_ARRAY1 (managed arrays) - 2048 allocations (4194304 bytes each)\n",
      "Done!\n",
      "\n",
      "ARGOUTVIEW_ARRAY1 (unmanaged, leaking) - 2048 allocations (4194304 bytes each)\n",
      "Step 483 failed"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "The unmanaged array leaks memory every time the array view is deleted.\n",
      "The managed one will delete the memory block seamlessly. This was tested\n",
      "both in Windows XP and Linux.\n",
      "\n",
      "A simple ARGOUTVIEWM\\_ARRAY2 example\n",
      "------------------------------------\n",
      "\n",
      "The following examples shows how to return a two-dimensional array from\n",
      "C which also benefits from the automatic memory deallocation.\n",
      "\n",
      "A naive \"crop\" function is wrapped using SWIG/numpy.i and returns a\n",
      "slice of the input array. When used as \\`array\\_out =\n",
      "crop.crop(array\\_in, d1\\_0,d1\\_1, d2\\_0,d2\\_1)\\`, it is equivalent to\n",
      "the native numpy slicing \\`array\\_out = array\\_in[d1\\_0:d1\\_1,\n",
      "d2\\_0:d2\\_1]\\`.\n",
      "\n",
      "### The C source (crop.c and crop.h)\n",
      "\n",
      "Here is the\n",
      "[crop.h](http://ezwidgets.googlecode.com/svn/trunk/numpy/crop.h) file:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "void crop(int *arr_in, int dim1, int dim2, int d1_0, int d1_1, int d2_0, int d2_1, int **arr_out, int *dim1_out, int *dim2_out);"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Here is the\n",
      "[crop.c](http://ezwidgets.googlecode.com/svn/trunk/numpy/crop.c) file:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "#include <stdlib.h>\n",
      "#include <errno.h>\n",
      "\n",
      "#include \"crop.h\"\n",
      "\n",
      "void crop(int *arr_in, int dim1, int dim2, int d1_0, int d1_1, int d2_0, int d2_1, int **arr_out, int *dim1_out, int *dim2_out)\n",
      "{\n",
      "    int *arr=NULL;\n",
      "    int dim1_o=0;\n",
      "    int dim2_o=0;\n",
      "    int i,j;\n",
      "\n",
      "    //value checks\n",
      "    if ((d1_1 < d1_0) || (d2_1 < d2_0) ||\n",
      "        (d1_0 >= dim1) || (d1_1 >= dim1) || (d1_0 < 0) || (d1_1 < 0) ||\n",
      "        (d2_0 >= dim2) || (d2_1 >= dim2) || (d2_0 < 0) || (d2_1 < 0))\n",
      "    {\n",
      "        errno = EPERM;\n",
      "        goto end;\n",
      "    }\n",
      "\n",
      "    //output sizes\n",
      "    dim1_o = d1_1-d1_0;\n",
      "    dim2_o = d2_1-d2_0;\n",
      "\n",
      "    //memory allocation\n",
      "    arr = (int *)malloc(dim1_o*dim2_o*sizeof(int));\n",
      "    if (arr == NULL)\n",
      "    {\n",
      "        errno = ENOMEM;\n",
      "        goto end;\n",
      "    }\n",
      "\n",
      "    //copying the cropped arr_in region to arr (naive implementation)\n",
      "    printf(\"\\n--- d1_0=%d d1_1=%d (rows)  -- d2_0=%d d2_1=%d (columns)\\n\",d1_0,d1_1,d2_0,d2_1);\n",
      "    for (j=0; j<dim1_o; j++)\n",
      "    {\n",
      "        for (i=0; i<dim2_o; i++)\n",
      "        {\n",
      "            arr[j*dim2_o+i] = arr_in[(j+d1_0)*dim2+(i+d2_0)];\n",
      "            printf(\"%d \",arr[j*dim2_o+i]);\n",
      "        }\n",
      "        printf(\"\\n\");\n",
      "    }\n",
      "    printf(\"---\\n\\n\");\n",
      "\n",
      "end:\n",
      "    *dim1_out = dim1_o;\n",
      "    *dim2_out = dim2_o;\n",
      "    *arr_out = arr;\n",
      "}"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "### The interface file (crop.i)\n",
      "\n",
      "The file (available here:\n",
      "[crop.i](http://ezwidgets.googlecode.com/svn/trunk/numpy/crop.i)) does a\n",
      "couple of interesting things: \\* The array dimensions DIM1 and DIM2 are\n",
      "in the same order as array.shape on the Python side. In a row major\n",
      "array definition for an image, DIM1 would the number of rows and DIM2\n",
      "the number of columns. \\* Using the errno library, An exception is\n",
      "generated when memory allocation fails (ENOMEM) or when a problem occurs\n",
      "with the indexes (EPERM)."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "%module crop\n",
      "%{\n",
      "#include <errno.h>\n",
      "#include \"crop.h\"\n",
      "\n",
      "#define SWIG_FILE_WITH_INIT\n",
      "%}\n",
      "\n",
      "%include \"numpy.i\"\n",
      "\n",
      "%init %{\n",
      "    import_array();\n",
      "%}\n",
      "\n",
      "%exception crop\n",
      "{\n",
      "    errno = 0;\n",
      "    $action\n",
      "\n",
      "    if (errno != 0)\n",
      "    {\n",
      "        switch(errno)\n",
      "        {\n",
      "            case EPERM:\n",
      "                PyErr_Format(PyExc_IndexError, \"Index error\");\n",
      "                break;\n",
      "            case ENOMEM:\n",
      "                PyErr_Format(PyExc_MemoryError, \"Not enough memory\");\n",
      "                break;\n",
      "            default:\n",
      "                PyErr_Format(PyExc_Exception, \"Unknown exception\");\n",
      "        }\n",
      "        SWIG_fail;\n",
      "    }\n",
      "}\n",
      "\n",
      "%apply (int* IN_ARRAY2, int DIM1, int DIM2) {(int *arr_in, int dim1, int dim2)}\n",
      "%apply (int** ARGOUTVIEWM_ARRAY2, int* DIM1, int* DIM2) {(int **arr_out, int *dim1_out, int *dim2_out)}\n",
      "\n",
      "%include \"crop.h\""
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Don't forget that you will need the\n",
      "[numpy.i](http://ezwidgets.googlecode.com/svn/trunk/numpy/numpy.i) file\n",
      "in the same directory for this to compile.\n",
      "\n",
      "### Setup file (setup\\_crop.py)\n",
      "\n",
      "This is the\n",
      "[setup\\_crop.py](http://ezwidgets.googlecode.com/svn/trunk/numpy/setup_crop.py)\n",
      "file:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "#! /usr/bin/env python\n",
      "\n",
      "# System imports\n",
      "from distutils.core import *\n",
      "from distutils      import sysconfig\n",
      "\n",
      "# Third-party modules - we depend on numpy for everything\n",
      "import numpy\n",
      "\n",
      "# Obtain the numpy include directory.  This logic works across numpy versions.\n",
      "try:\n",
      "    numpy_include = numpy.get_include()\n",
      "except AttributeError:\n",
      "    numpy_include = numpy.get_numpy_include()\n",
      "\n",
      "# crop extension module\n",
      "_crop = Extension(\"_crop\",\n",
      "                   [\"crop.i\",\"crop.c\"],\n",
      "                   include_dirs = [numpy_include],\n",
      "\n",
      "                   extra_compile_args = [\"--verbose\"]\n",
      "                   )\n",
      "\n",
      "# NumyTypemapTests setup\n",
      "setup(  name        = \"crop test\",\n",
      "        description = \"A simple crop test to demonstrate the use of ARGOUTVIEWM_ARRAY2\",\n",
      "        author      = \"Egor Zindy\",\n",
      "        version     = \"1.0\",\n",
      "        ext_modules = [_crop]\n",
      "        )"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "### Testing the module\n",
      "\n",
      "If everything goes according to plan, there should be a \\`\\_crop.pyd\\`\n",
      "file available in the \\`build\\\\lib.XXX\\` directory. The file needs to be\n",
      "copied in the directory with the \\`crop.py\\` file (generated by swig).\n",
      "\n",
      "A python test program is provided in the SVN repository\n",
      "([test\\_crop.py](http://ezwidgets.googlecode.com/svn/trunk/numpy/test_crop.py))\n",
      "and reproduced below:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "import crop\n",
      "import numpy\n",
      "\n",
      "a = numpy.zeros((5,10),numpy.int)\n",
      "a[numpy.arange(5),:] = numpy.arange(10)\n",
      "\n",
      "b = numpy.transpose([(10 ** numpy.arange(5))])\n",
      "a = (a*b)[:,1:] #this array is most likely NOT contiguous\n",
      "\n",
      "print a\n",
      "print \"dim1=%d dim2=%d\" % (a.shape[0],a.shape[1])\n",
      "\n",
      "d1_0 = 2\n",
      "d1_1 = 4\n",
      "d2_0 = 1\n",
      "d2_1 = 5\n",
      "\n",
      "c = crop.crop(a, d1_0,d1_1, d2_0,d2_1)\n",
      "d = a[d1_0:d1_1, d2_0:d2_1]\n",
      "\n",
      "print \"returned array:\"\n",
      "print c\n",
      "\n",
      "print \"native slicing:\"\n",
      "print d"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "This is what the output looks like:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "$ python test_crop.py \n",
      "[[    1     2     3     4     5     6     7     8     9]\n",
      " [   10    20    30    40    50    60    70    80    90]\n",
      " [  100   200   300   400   500   600   700   800   900]\n",
      " [ 1000  2000  3000  4000  5000  6000  7000  8000  9000]\n",
      " [10000 20000 30000 40000 50000 60000 70000 80000 90000]]\n",
      "dim1=5 dim2=9\n",
      "\n",
      "--- d1_0=2 d1_1=4 (rows)  -- d2_0=1 d2_1=5 (columns)\n",
      "200 300 400 500 \n",
      "2000 3000 4000 5000 \n",
      "---\n",
      "\n",
      "returned array:\n",
      "[[ 200  300  400  500]\n",
      " [2000 3000 4000 5000]]\n",
      "native slicing:\n",
      "[[ 200  300  400  500]\n",
      " [2000 3000 4000 5000]]"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "numpy.i takes care of making the array contiguous if needed, so the only thing left to take care of is the array orientation. \n",
      "\n",
      "## Conclusion and comments\n",
      "\n",
      "That's all folks! Files are available on the [http://code.google.com/p/ezwidgets/source/browse/#svn/trunk/numpy Google code SVN]. As usual, comments welcome!\n",
      "\n",
      "Regards,\n",
      "Egor"
     ]
    }
   ],
   "metadata": {}
  }
 ]
}